#ifndef __MARS_RENDER_INTERFACE_H__
#define __MARS_RENDER_INTERFACE_H__

namespace Graphics
{

struct SamplerStateEI
{

};

struct RasterizerStateEI
{

};

struct DepthStencilStateEI
{

};

struct BlendStateEI
{

};
	
#define DEFINE_RI_TYPE_MACRO_UNWIND( MACRO_DEFINE ) \
	MACRO_DEFINE( SamplerState, None ) \
	MACRO_DEFINE( RasterizerState, None ) \
	MACRO_DEFINE( DepthStencilState, None ) \
	MACRO_DEFINE( BlendState, None ) \
	MACRO_DEFINE( VertexDeclaration, None ) \
	MACRO_DEFINE( VertexShader, None ) \
	MACRO_DEFINE( PixelShader, None ) \
	MACRO_DEFINE( VRamBuffer, None ) \
	MACRO_DEFINE( BoundShaderProgram, None ) \
	MACRO_DEFINE( Surface, None ) \
	MACRO_DEFINE( Texture, None ) \
	MACRO_DEFINE( Texture2D, Texture ) \
	MACRO_DEFINE( TextureCube, Texture ) \
	MACRO_DEFINE( Viewport, None ) 
	
enum RenderInterfaceType
{
	RIT_None = -1,
#define DEFINE_RI_TYPE( type, parent ) RIT_##type,
	DEFINE_RI_TYPE_MACRO_UNWIND( DEFINE_RI_TYPE )
#undef DEFINE_RI_TYPE
	RIT_Count
};

template< RenderInterfaceType ResourceType >
class TRIResourceReference;

template< RenderInterfaceType ResourceType > 
class TRIResource
{
};

#define DEFINE_RI_RESOURCE_REF( type, parent ) \
	template<> class TRIResource< RIT_##type > : public TRIResource< RIT_##parent > {}; \
	typedef TRIResource< RIT_##type >* type##RIParamRef; \
	typedef TRIResourceReference< RIT_##type > type##RIRef;
	
DEFINE_RI_TYPE_MACRO_UNWIND(DEFINE_RI_RESOURCE_REF);

class RenderInterface
{
public:
	SamplerStateRIRef				CreateSamplerState( const SamplerStateEI& samplerState ) = 0;
	RasterizerStateRIRef			CreateRasterizerState( const RasterizerStateEI& rasterizerState ) = 0;
	DepthStencilStateRIRef			CreateDepthStencilState( const DepthStencilStateEI& depthStencilState ) = 0;
	BlendStateRIRef					CreateBlendState( const BlendStateEI& blendState ) = 0;
	VertexDeclarationRIRef			CreateVertexDeclaration( const VertexDeclarationElementList& elements ) = 0;
	VertexShaderRIRef				CreateVertexShader( const uint8* code ) = 0;
	PixelShaderRIRef				CreatePixelShader( const uint8* code ) = 0;
	BoundShaderProgramRIRef			CreateBoundShaderProgram( VertexDeclarationRIParamRef vertexDeclaration,
															  uint32* streamStrides,
															  VertexShaderRIParamRef vertexShader,
															  PixelShaderRIParamRef pixelShader );
	VRamBufferRIRef					CreateVRamBuffer( uint32 stride, uint32 size, uint32 usage, uint32& numInstance ) = 0;
	void*							LockVRamBuffer( VRamBufferRIParamRef buffer, uint32 offset, uint32 size ) = 0;
	void							UnlockVRamBuffer( VRamBufferRIParamRef buffer ) = 0;
	
	Texture2DRIRef					CreateTexture2D( uint32 sizeX, uint32 sizeY, uint8 format, uint32 numMips, uint32 flags, );
	
	void*							LockTexture2D( Texture2DRIParamRef texture, uint32 mipIndex, bool bIsDataBeingWrittenTo, uint32& destStride, bool bLockWithinMiptail ) = 0;
	
	void							UnlockTexture2D( Texture2DRIParamRef texture, uint32 mipIndex, bool ) = 0;
	bool							UpdateTexture2D( Texture2DRIParamRef texture, uint32 mipIndex, uint32 n, );
	
	Texture2DRIRef					GetResolveTarget( SurfaceRIParamRef surface ) = 0;
	
	void							CopyTexture2D( Texture2DRIParamRef dstTexture, uint32 mipIndex, int baseSizeX, int baseSizeY, int format, const std::vector<> regions );
	
	TextureCubeRIRef				CreateTextureCube( uint32 size, uint8 format, uint32 numMips, uint32 flags, ) = 0;
	void*							LockTextureCubeFace( TextureCubeRIParamRef texture, uint32 faceIndex, uint32 mipIndex, bool , uint32& destStride, bool bLockWithinMiptail ) = 0;
	void							UnlockTextureCube( TextureCubeRIParamRef texture, uint32 faceIndex, uint32 mipIndex, bool bLockWithinMiptail ) = 0;

SurfaceRIRef					CreateSurface( uint32 sizeX, uint32 sizeY, uint8 format, Texture2DRIParamRef resovleTargetTexture, uint32 flags );
SurfaceRIRef					CreateSurfaceCube( uint32 sizeX, uint8 format, TextureCubeRIParamRef resovleTargetTexture, CubeFace face, uint32 flags );

void CopyToResolveTarget( SurfaceRIParamRef source, bol bKeepOriginalSurface, ResolveParams& resolveParams ) = 0;
void CopyFromResolveTarget( SurfaceRIParamRef destSurface ) = 0;

void BeginDrawingViewport( ViewportRIParamRef viewport ) = 0;
void EndDrawingViewport( ViewportRIParamRef viewport, bool bPresent, bool bLockToVsync ) = 0;
bool IsDrawingViewport() = 0;
SurfaceRIRef GetViewportBackBuffer( ViewportRIParamRef viewport ) = 0;
void BeginScene() = 0;
void EndScene() = 0;

ViewportRIParamRef CreateViewport( void* handle, uint32 sizeX, uint32 sizeY, bool bIsFullScreen ) = 0;

void ResizeViewport( ViewportRIParamRef viewport, uint32 sizeX, uint32 sizeY, bool bIsFullScreen ) = 0;

void Tick( float deltaTime ) = 0;

void SetStreamSource( uint32 streamIndex, VRamBufferRIParamRef vertexBuffer, uint32 stride, bool bUseInstanceIndex, uint32 numVerticesPerIndex, uint32 numInstance ) = 0;

void SetRasterizerState( RasterizerStateRIParamRef state ) = 0;
void SetRasterizerStateImmediate( RasterizerStateEI initializer ) = 0;
void SetViewport( uint32 minX, uint32 minY, float minZ, uint32 maxX, uint32 maxY, float maxZ ) = 0;
void SetScissorRect( bool bEnable, uint32 minX, uint32 minY, uint32 maxX, uint32 maxY ) = 0;
void SetDepthBoundsTest(  );

void SetBoundShaderProgram( BoundShaderProgramRIParamRef boundShaderProgram ) = 0;

void SetSamplerState( PixelShaderRIParamRef pixelShader, uint32 textureIndex, uint32 samplerIndex, SamplerStateRIParamRef state, TextureRIParamRef texture, float mipBias, float largestMip, float smallestMip ) = 0;

void SetVertexShaderParameter( VertexShaderRIParamRef vertexShader, uint32 bufferIndex, uint32 baseIndex, uint32 numBytes, const void* newValue, const char* paramName ) = 0;
void SetVertexShaderBoolParameter( VertexShaderRIParamRef vertexShader, uint32 bufferIndex, uint32 baseIndex, bool newValue ) = 0;
void SetVertexShaderFloatArray( VertexShaderRIParamRef vertexShader, uint32 bufferIndex, uint32 baseIndex, uint32 numValues, const float* pFloatValues, const char* paramName );

void SetPixelShaderParameter( PixelShaderRIParamRef pixelShader, uint32 bufferIndex, uint32 baseIndex, uint32 numBytes, const void* newValue, const char* paramName ) = 0;
void SetPixelShaderBoolParameter( PixelShaderRIParamRef pixelShader, uint32 bufferIndex, uint32 baseIndex, bool newValue ) = 0;

void SetRenderTargetBias( float colorBias ) = 0;

void SetViewParameters( );

void SetShaderRegisterAllocation( uint32 numVertexShaderRegisters, uint32 numPixelShaderRegisters ) = 0;

void SetDepthStencilState( DepthStencilStateRIParamRef state ) = 0;
void SetBlendState( BlendStateRIParamRef state ) = 0;
void SetMRTBlendState( BlendStateRIParamRef state ) = 0;

void SetRenderTarget( SurfaceRIParamRef renderTarget, SurfaceRIParamRef depthStencilTarget ) = 0;

void SetColorWriteEnable( bool bEnable ) = 0;
void SetColorWriteMask( uint32 colorWriteMask ) = 0;
void SetMRTColorWriteEnable( bool bEnable, uint32 targetIndex ) = 0;

void DrawPrimitive( uint32 primitiveType, uint32 baseVertexIndex, uint32 numPrimitives ) = 0;
void DrawIndexedPrimitive( VRamBufferRIParamRef indexBuffer, uint32 primitiveType, uint32 baseVertexIndex, uint32 minIndex, uint32 numVertices, uint32 startIndex, uint32 numPrimitives ) = 0;

void DrawIndexedPrimitive_PerVertexShaderCulling( VRamBufferRIParamRef indexBuffer, uint32 primitiveType, uint32 baseVertexIndex, uint32 minIndex, uint32 numVertices, uint32 startIndex, uint32 numPrimitives, const Matrix& localToWorld, const void* ) = 0;

void BeginDrawPrimitiveUP( uint32 primitiveType, uint32 numPrimitives, uint32 numVertices, uint32 vertexDataStride, void*& outVertexData ) = 0;
void EndDrawPrimitiveUP() = 0;

void DrawPrimitiveUP( uint32 primitiveType, uint32 numPrimitives, const void* vertexData, uint32 vertexDataStride ) = 0;
void BeginDrawIndexedPrimitiveUP( uint32 primitiveType, uint32 numPrimitives, uint32 numVertices, uint32 vertexDataStride, void*& outVertexData, uint32 minVertexIndex, uint32 numIndices, uint32 indexDataStride, void*& outIndexData ) = 0;
void EndDrawIndexedPrimitiveUP() = 0;

void DrawIndexedPrimitiveUP( uint32 primitiveTYpe, uint32 minVertexIndex, uint32 numVertices, uint32 numPrimitives, const void* indexData, uint32 indexDataStride, const void* vertexData, uint32 vertexDataStride ) = 0;

void DrawSpriteParticles( const mesh ) = 0;
void DrawSubUVParticles( const mesh ) = 0;

void Clear( bool bClearColor, const Color color, bool bClearDepth, float depth, bool bClearStencil, uint32 stencil ) = 0;

void KickCommandBuffer() = 0;
void BlockUntilGPUIdle() = 0;

void SuspendRendering() = 0;
void ResumeRendering() = 0;

bool IsRenderingSuspended() = 0;

void MSAAInitPrepass() = 0;
void MSAAFixViewport() = 0;

void MSAABeginRendering( bool bRequiresClear ) = 0;
void MASSEndRendering( Texture2DRIParamRef depthTexture, Texture2DRIParamRef colorTexture, uint32 viewIndex ) = 0;


};
	
extern bool InitRenderInterface();
extern void ExitRenderInterface();
	
extern bool	GIsRenderInterfaceInit;
extern RenderInterface GRenderInterface;

template<RenderInterfaceType ResourceType>
class TRIResourceReference
{
public:
	typedef TRIResource<ResourceType>* ReferenceType;

	TRIResourceReference()
	: m_ref( NULL )
	{}

	TRIResourceReference( ReferenceType inRef )
	{
		m_ref = inRef;
		if ( m_ref )
		{
			GDynamicRHI->AddResourceRef( m_ref );
		}
	}

	TRIResourceReference( const TRIResourceReference& inRef )
	{
		m_ref = inRef.m_ref;
		if ( m_ref )
		{
			GDynamicRHI->AddResourceRef( m_ref );
		}
	}

	~TDynamicRHIResourceReference()
	{
		if ( m_ref )
		{
			GDynamicRHI->RemoveResourceRef( m_ref );
		}
	}

	TDynamicRHIResourceReference& operator = ( ReferenceType inRef )
	{
		ReferenceType oldReference = inRef;
		if ( inRef )
		{
			GDynamicRHI->AddResourceRef( inRef );
		}
		m_ref = inRef;
		if ( oldReference )
		{
			GDynamicRHI->RemoveResourceRef( oldReference );
		}
		return *this;
	}

	TRIResourceReference& operator = (const TRIResourceReference& inRef )
	{
		return *this = rhs.m_ref;
	}

	bool operator == ( const TRIResourceReference& other ) const
	{
		return m_ref == other.m_ref;
	}

	void* operator -> () const
	{
		return m_ref;
	}

	operator ReferenceType () const
	{
		return m_ref;
	}

	void SafeRelease()
	{
		*this = NULL;
	}
	
	Core::uint32 GetRefCount()
	{
		if ( m_ref )
		{
			return GDynamicRHI->GetRefCount( m_ref );
		}
		else
		{
			return 0;
		}
	}
	
public:
	friend Core::uint32 GetTypeHash( ReferenceType ref )
	{
		return PointerHash( ref );
	}
	
	friend bool IsValidRef( const TRIResourceReference& ref )
	{
		return ref.m_ref != NULL;
	}
	

private:
	ReferenceType m_ref;
};

} // end of namespace Graphics

#endif // end of #ifndef __MARS_RENDER_INTERFACE_H__